using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Effects;
using GraphMyCode.Controls.Shaders;

namespace GraphMyCode.Controls
{
	internal class TransformationService
	{
		private readonly AnimationService animationService;
		private readonly TranslateTransform dragTransform;
		private readonly GraphControl graph;
		private readonly TranslateTransform miniMapDragTransform;
		private readonly ScaleTransform miniMapZoomTransform;
		//private readonly PlaneProjection parentProjection;
		private readonly ScaleTransform zoomTransform;

		public TransformationService(
			GraphControl graph,
			ScaleTransform zoomTransform,
			TranslateTransform dragTransform,
			TranslateTransform miniMapDragTransform, 
			ScaleTransform miniMapZoomTransform, 
			PlaneProjection parentProjection)
		{
			this.graph = graph;
			this.miniMapDragTransform = miniMapDragTransform;
			this.dragTransform = dragTransform;
			this.zoomTransform = zoomTransform;
			this.miniMapZoomTransform = miniMapZoomTransform;
			//this.parentProjection = parentProjection;

			animationService = new AnimationService(zoomTransform, dragTransform, parentProjection);
			animationService.AnimationFinished += AnimationServiceAnimationFinished;
		}

		private double graphScale;
		public double GraphScale
		{
			get { return graphScale; }
			set
			{
				graphScale = value;
				animationService.GraphScale = graphScale;
			}
		}

		private void AnimationServiceAnimationFinished(object sender, AnimationFinishedEventArgs e)
		{
			graph.ParentPanel.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));

			graph.ZoomPercentage = e.ZoomValue;
			TranslateMiniMap(-e.TranslateX, -e.TranslateY);
			graph.RenderMiniMap();
		}

		internal void Virtualize()
		{
			GeneralTransform gt = graph.MiniMapBorder.TransformToVisual(graph.ParentPanel);
			Point topLeft = gt.Transform(new Point(0, 0));
			Point bottomRight = gt.Transform(new Point(graph.MiniMapBorder.ActualWidth, graph.MiniMapBorder.ActualHeight));

			var visibleRect = new Rect(topLeft, bottomRight);

			foreach (object item in graph.Items)
			{
				GraphItem gItem = graph.GetItem(item);
				if (gItem != null)
				{
					gItem.Visibility =
						visibleRect.IntersectsWith(gItem.Bounds)
							? Visibility.Visible
							: Visibility.Collapsed;
				}
			}
		}

		internal void DeVirtualize()
		{
			foreach (object item in graph.Items)
			{
				GraphItem gItem = graph.GetItem(item);
				if (gItem != null)
					gItem.Visibility = Visibility.Visible;
			}
		}

		internal void Zoom(double zoomValue)
		{
			zoomTransform.ScaleX = zoomValue;
			zoomTransform.ScaleY = zoomValue;

			miniMapZoomTransform.ScaleX = 1.0 / zoomValue;
			miniMapZoomTransform.ScaleY = 1.0 / zoomValue;

			//Virtualize();
		}

		internal void Translate(double x, double y)
		{
			dragTransform.X = x;
			dragTransform.Y = y;
			miniMapDragTransform.X = -x;
			miniMapDragTransform.Y = -y;

			//Virtualize();
		}

		internal void TranslateMiniMap(double x, double y)
		{
			miniMapDragTransform.X = x;
			miniMapDragTransform.Y = y;
		}

		internal void MoveTranslate(double x, double y)
		{
			dragTransform.X += x;
			dragTransform.Y += y;

			miniMapDragTransform.X -= x;
			miniMapDragTransform.Y -= y;

			//Virtualize();
		}

		internal void TranslateZoomAnimated(double x, double y, double zoomValue, double oldZoomValue)
		{
			//DeVirtualize();
			graph.ParentPanel.Background = new ImageBrush
											{
												ImageSource = new WriteableBitmap(graph.ParentPanel, null),
												Stretch = Stretch.Uniform
											};

			//graph.ParentPanel.Effect = new SmoothMagnify();

			//foreach (object item in graph.Items)
			//{
			//    GraphItem gItem = graph.GetItem(item);
			//    if (gItem != null)
			//        gItem.Visibility = Visibility.Collapsed;
			//}

			animationService.MoveAnimated(x, y, zoomValue, oldZoomValue);
		}
	}
}